function dataURLtoBlob(base64) {
    var bstr = atob(base64), n = bstr.length, u8arr = new Uint8Array(n);

    while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
    }
    return new Blob([u8arr], { type: 'data:audio/wav;base64' }).arrayBuffer();
}
export class AudioComponent {
    constructor(config) {
        // 初始化音频上下文。
        const AudioContext = window.AudioContext;
        this.audioContext = new AudioContext();

        /**
         * @type { AudioBufferSourceNode } 每次切换音频都要重新创建一个。
         */
        this.source = null;
        /**
         * @type { Map<string, AudioBuffer> }
         */
        this.map = new Map;
        this.config = config;

    }

    /**
     * 绑定函数为异步函数，需要等所以绑定结束后，才能start
     * @param {string} name 音频名称 
     * @param {string} base64 
     */
    async bind(name, base64) {
        const buffer = await dataURLtoBlob(base64);
        const audioBuffer = await this.audioContext.decodeAudioData(buffer);
        this.map.set(name, audioBuffer);
    }

    setConfig() {
        if (typeof config === 'object') {
            const { loop } = config;
            this.source.loop = loop;
        }
    }

    /**
     * 注意在一次AudioBufferSourceNode生命周期中，start只能调用一次
     * 所以调用stop后，如果再次调用start会重新创建AudioBufferSourceNode，不能断点续播。
     * @todo 未来如果有需求可能会增加断点续播。
     * @param {string} name 音频名称 
     */
    start(name) {
        if (this.source instanceof AudioBufferSourceNode) {
            this.source.stop();
        }
        this.source = this.audioContext.createBufferSource();
        this.source.connect(this.audioContext.destination);
        this.setConfig();
        this.source.buffer = this.map.get(name);
        this.source.start();
    }

    /**
     * 注意，不能停止没有播放的AudioBufferSourceNode。
     */
    stop() {
        this.source.stop();
    }
}